﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Manager.General;
using System.Diagnostics;
using System.IO;

namespace Manager.Tools.Dig
{
    /// <summary>
    /// Dig executer form
    /// </summary>
    public partial class DigForm : Form
    {
        private DataTable optionsTable;

        /// <summary>
        /// Initializes a new instance of the <see cref="DigForm"/> class.
        /// </summary>
        public DigForm()
        {
            InitializeComponent();

            FillTypesComboBox();
            FillClassComboBox();
        }

        /// <summary>
        /// Fills the class combo box.
        /// </summary>
        private void FillClassComboBox()
        {
            foreach (RecordClass type in Enum.GetValues(typeof(RecordClass)))
            {
                classComboBox.Items.Add(type);
            }
        }

        /// <summary>
        /// Fills the types combo box.
        /// </summary>
        private void FillTypesComboBox()
        {
            foreach (RecordTypes type in Enum.GetValues(typeof(RecordTypes)))
            {
                typesComboBox.Items.Add(type);
            }
            typesComboBox.SelectedIndex = 0;
        }

        /// <summary>
        /// Handles the CheckedChanged event of the optionsCheckBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void optionsCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            optionsGroupBox.Enabled = optionsCheckBox.Checked;
        }

        /// <summary>
        /// Handles the Click event of the executeButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void executeButton_Click(object sender, EventArgs e)
        {
            try
            {
                executionStatusToolStripStatusLabel.Text = "Execution status: dig querying...";
                executeButton.Enabled = false;

                string digPath = Path.Combine(Properties.Settings.Default.BindDirectoryPath, @"bin\dig.exe");
                string argument = string.Format("{0} {1} {2} {3}",
                                                serverTextBox.Text,
                                                domainTextBox.Text,
                                                typesComboBox.Text,
                                                classComboBox.Text);

                argument += GetOptionArguments(argument);

                digExecuterBackgroundWorker.RunWorkerAsync(new string[] {digPath, argument});
            }
            catch
            {
                
            }
        }

        /// <summary>
        /// Gets the option arguments.
        /// </summary>
        /// <param name="argument">The argument.</param>
        /// <returns></returns>
        private string GetOptionArguments(string argument)
        {
            if(string.IsNullOrEmpty(argument))
            {
                return string.Empty;
            }

            if (optionsTable == null)
            {
                return string.Empty;
            }

            StringBuilder optionArgs = new StringBuilder(3);

            foreach(DataRow row in optionsTable.Rows)
            {
                optionArgs.Append("+");

                if(HasOptionArguments(row))
                {
                    optionArgs.AppendFormat("{0}={1}", row["Option"].ToString(), row["Value"].ToString());
                }
                else if((bool)row["Enabled"])
                {
                    optionArgs.Append(row["Option"].ToString());
                }
                else
                {
                    optionArgs.AppendFormat("no{0}", row["Option"].ToString());
                }

                optionArgs.Append(" ");
            }
            return optionArgs.ToString();
        }

        /// <summary>
        /// Determines whether [has option arguments] [the specified row].
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns>
        /// 	<c>true</c> if [has option arguments] [the specified row]; otherwise, <c>false</c>.
        /// </returns>
        private static bool HasOptionArguments(DataRow row)
        {
            string[] haveArguments = {"domain","time", "tries", "retry", "ndots",
                                      "bufsize", "edns", "trusted-key"};
            foreach(string argument in haveArguments)
            {
                if(argument.Equals(row["Option"].ToString(), StringComparison.InvariantCulture))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Handles the SelectedIndexChanged event of the optionsComboBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void optionsComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            optionDescripitonLabel.Text = ContentDescription.GetDigOptionDescription(optionsComboBox.Text);
        }

        /// <summary>
        /// Handles the Click event of the optionAddButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void optionAddButton_Click(object sender, EventArgs e)
        {
            // Create table
            if(optionsTable == null)
            {
                optionsTable = new DataTable();
                optionsTable.Columns.Add("Option", typeof (string));
                optionsTable.Columns.Add("Enabled", typeof(bool));
                optionsTable.Columns.Add("Value", typeof(string));
            }

            DataRow row = optionsTable.NewRow();
            row["Option"] = optionsComboBox.Text;
            row["Enabled"] = false;
            optionsTable.Rows.Add(row);

            optionsDataGridView.DataSource = optionsTable;
        }

        /// <summary>
        /// Disables the argument cells.
        /// </summary>
        /// <param name="rowindex">The rowindex.</param>
        private void DisableArgumentCells(int rowindex)
        {
            if (HasOptionArguments(optionsTable.Rows[rowindex]))
            {
                optionsDataGridView.Rows[rowindex].Cells["Enabled"].ReadOnly = true;
                DataGridViewCellStyle style = new DataGridViewCellStyle();
                style.BackColor = SystemColors.ControlDark;
                style.ForeColor = SystemColors.GrayText;
                optionsDataGridView.Rows[rowindex].Cells["Enabled"].Style = style;
            }
            else
            {
                optionsDataGridView.Rows[rowindex].Cells["Value"].ReadOnly = true;
                DataGridViewCellStyle style = new DataGridViewCellStyle();
                style.BackColor = SystemColors.ControlDark;
                style.ForeColor = SystemColors.GrayText;
                optionsDataGridView.Rows[rowindex].Cells["Value"].Style = style;
            }
        }

        /// <summary>
        /// Handles the RowPrePaint event of the optionsDataGridView control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewRowPrePaintEventArgs"/> instance containing the event data.</param>
        private void optionsDataGridView_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
        {
            DisableArgumentCells(e.RowIndex);
        }

        /// <summary>
        /// Handles the DoWork event of the digExecuterBackgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
        private void digExecuterBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {

            try
            {
                string[] parameters = (string[]) e.Argument;

                ProcessStartInfo startInfo = new ProcessStartInfo(parameters[0], parameters[1]);
                startInfo.UseShellExecute = false;
                startInfo.ErrorDialog = false;
                startInfo.CreateNoWindow = true;
                startInfo.RedirectStandardOutput = true;

                using (Process digProcess = Process.Start(startInfo))
                {
                    if(e.Cancel)
                    {
                        digProcess.Kill();
                        return;
                    }
                    using (StreamReader output = digProcess.StandardOutput)
                    {
                        e.Result = output.ReadToEnd();
                    }
                }
            }
            catch(Exception ex)
            {
                e.Result = "Execution error\n" + ex.Message;
            }
        }

        /// <summary>
        /// Handles the RunWorkerCompleted event of the digExecuterBackgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
        private void digExecuterBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            resultsTextBox.Text = e.Result.ToString();
            digTabControl.SelectTab(resultsTabPage);

            executionStatusToolStripStatusLabel.Text = "Execution status: finished";
            executeButton.Enabled = true;
        }

        private void DigForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            digExecuterBackgroundWorker.CancelAsync();
        }

    }
}
